﻿Imports System.Threading

Friend Class ReaderWriterLockStrategy
  Implements IDisposable
  Implements ILockStrategy

  Private _lock As New ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion)

  Public Function GetReadLock() As ISharedCollectionLock Implements ILockStrategy.GetReadLock
    EnsureNotDisposed()
    _lock.EnterReadLock()
    Return New ReaderWriterSlimLock(_lock)
  End Function

  Public Function GetWriteLock() As ISharedCollectionLock Implements ILockStrategy.GetWriteLock
    EnsureNotDisposed()
    _lock.EnterWriteLock()
    Return New ReaderWriterSlimLock(_lock)
  End Function

  Public ReadOnly Property ThreadCanRead() As Boolean Implements ILockStrategy.ThreadCanRead
    Get
      EnsureNotDisposed()
      Return _lock.IsReadLockHeld OrElse _lock.IsWriteLockHeld 'todo uncomment if upgradelock is used OrElse _lock.IsUpgradeableReadLockHeld
    End Get
  End Property

  Public ReadOnly Property ThreadCanWrite() As Boolean Implements ILockStrategy.ThreadCanWrite
    Get
      EnsureNotDisposed()
      Return _lock.IsWriteLockHeld
    End Get
  End Property

  Public ReadOnly Property SupportsConcurrentReads() As Boolean Implements ILockStrategy.SupportsConcurrentReads
    Get
      Return True
    End Get
  End Property

#Region "IDisposable Support"

  Private Sub EnsureNotDisposed()
    If _isDisposed Then
      Throw New ObjectDisposedException("ReaderWriterLockStrategy")
    End If
  End Sub

  Private _isDisposed As Boolean

  ' To detect redundant calls

  ' IDisposable
  Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    If Not Me._isDisposed Then
      If disposing Then
        'dispose managed state (managed objects).
      End If

      _lock.Dispose()
      _lock = Nothing
    End If
    Me._isDisposed = True
  End Sub

  Protected Overrides Sub Finalize()
    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    Dispose(False)
    MyBase.Finalize()
  End Sub

  ' This code added by Visual Basic to correctly implement the disposable pattern.
  Public Sub Dispose() Implements IDisposable.Dispose
    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region
End Class